home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 38
/
Amiga Format CD38 (1999-03-15)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-04].iso
/
-in_the_mag-
/
cuckoo99
/
scsiutil
/
scsiutil.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-02-05
|
72KB
|
2,730 lines
/*
***** SCSIutil
*
* A utility to do some low-level operations to a SCSI disk, e.g.
*
* - start/stop motor
* - read sectors
* - read disk capacity info
* - get inquiry info (manufacturers name etc)
* - seek to a sector's cylinder (use to park heads)
* - play audio tracks of a CD-DA
* - eject/insert a medium
* - read digital data off audio CDs (with Sony 8003 = Apple CD300
* and Toshiba 3401)
* - set output volume of a CD-ROM drive
*
* NOTE: this program is based on SCSI information taken from
* the accompanying documentation of a NEC D3841 SCSI disk.
* I don't know the extent to which SCSI standards are
* supported by that disk.
*
* These commands work on the above disk. But a seek to
* sector -1 (park on the NEC disk) fails on my Quantum 105.D
*
* Program returns:
* 1 - init didn't work (maybe allocmem failed, etc.)
* 2 - wrong parameter count
* 3 - wrong parameter
*
***** Written by Gary Duncan
*
* Bug reports etc via e-mail to gduncan@philips.oz.au) , or mail to
*
* Gary Duncan
* Philips PTS
* 23 Lakeside Dr
* Tally-Ho Technology Park
* Burwood East Vic 3151
* Australia
*
* New features and rewrites by:
*
* The Software Brewery
* Heiko Rath
* Raiffeisenstr.10a
* D-64331 Weiterstadt
* Germany
*
* EMail: hr@brewhr.swb.de
*
***** Freely distributable for non-commercial purposes
*
* Compiles under Lattice 6.50
* - needs AmigaDos 2.0 #includes
*
***** Thanks to Markus Illenseer for some beta-testing.
*
***** Function List :-
*
* breakcheck() by GD, modified by <HR>
* __chkabort() by <HR>
* DoScsiCmd () by <HR>
* err_str() by GD
* gcomp() by GD
* finddrivebrand() by <HR>
* GetDevName() by GD
* id2string () by <HR>
* init () by GD, modified by <HR>
* inquiry() by GD, modified by <HR>
* medium_removal() by <HR>
* mode_sense() by <HR>
* motor () by GD, modified by <HR>
* play_audio () by <HR>
* rawahexasciioutput() by <HR>
* rawhexoutput() by <HR>
* read_capacity() by GD, modified by <HR>
* read_cdblockheader() by <HR>
* read_cddaasync() by <HR>
* read_sec () by GD, modified by <HR>
* read_sec_scsi () by GD, modified by <HR>
* read_subchannel() by <HR>
* read_toc () by <HR>
* seek () by GD, modified by <HR>
* SendScsiCmd() by <HR>
* sense_errs() by GD
* set_volume() by <HR>
* usage() by GD, modified by <HR>
* WaitScsiCmd() by <HR>
*
*/
#define VERSION "2.02"
/*
**** Includes
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/execbase.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <devices/trackdisk.h>
#include <devices/scsidisk.h>
#include <libraries/dos.h>
#ifdef __SASC
#include <proto/all.h>
#else
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
/* non-ANSI C macro isascii() */
#define isascii(a) (((a) & 0x80) == 0)
#endif
#include "scsi_priv.h"
/*
* string for AmigaDOS Version Command
*/
char A_vers[] = "\0$VER: SCSIutil " VERSION " (" __DATE__ " " __TIME__ ")";
/*
**** Global variables
*/
UBYTE *ip_buf = NULL;
UBYTE *scsi_data = NULL;
UBYTE *toc_buf = NULL;
UBYTE *dev = "";
int scsi_id = -1; /* ID of the SCSI device to send commands to */
UBYTE *pname;
UBYTE buffer[LINE_BUF];
int secno = -1;
DRIVETYPE whatdrive = UNKNOWN; /* what CD-ROM brand */
UBYTE *cdda_buf[NDBLBUF];
MSGPORT *mp_ptr[NDBLBUF];
IOSTDREQ *io_ptr[NDBLBUF];
SCSICMD scsi_cmd[NDBLBUF];
UBYTE *scsi_sense[NDBLBUF];
UBYTE scsi_status[NDBLBUF];
BYTE *mono_buf[NDBLBUF];
#ifdef USE8SVX
BYTE write8svx = FALSE; /* convert to 8SVX */
#endif /* USE8SVX */
/*
**** Function descr.
*/
int breakcheck (void);
int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
UBYTE *err_str (int err);
void exit (int status);
void finddrivebrand (void);
int gcomp (char *p1, char *p2, int len);
UBYTE *GetDevName (char *grep);
UBYTE *id2string (int id, IDTOSTRING * idtable);
BOOLEAN init (void);
void inquiry (BOOLEAN parsedoutput);
void medium_removal(BOOLEAN lock);
void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
void motor (int motorstatus);
void play_audio (int starttrack, int startindex, int endtrack, int endindex);
void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
void rawhexoutput (UBYTE *p, UWORD numbytes);
void read_capacity (BOOLEAN parsed);
void read_cdblockheader (BOOLEAN parsed, ULONG block);
#ifdef _DCC
__stkargs
#endif
void read_cddaasync (ULONG startblock, ULONG numblocks, BYTE
whichchannel, BYTE use16bit, unsigned int subcode);
void read_sec (void);
void read_sec_scsi (void);
void read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track);
void read_toc (int toclong);
void seek (void);
UBYTE *sense_errs (int req, int err);
void set_volume (int vol0, int vol1, int vol2, int vol3);
void usage (void);
int WaitScsiCmd (int req);
void SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
#ifdef __SASC
void __regargs __chkabort (void);
#endif /* __SASC */
#ifdef _DCC
#include <stdlib.h>
typedef int (*brkfuncptr)();
int brkhandler() { return(0); }
#endif
/*********************************************************************
*
* main
*
*
*/
int
main (int argc, char **argv)
{
UBYTE *p;
int j = 0, i = 0;
int returnvalue = 0;
#ifdef _DCC
int (*oldbrkhandler)() = onbreak(brkhandler);
#endif
if (argc == 1)
{
usage ();
exit (1);
}
/*
* see if a SCSI.device specified
*/
if (strncmp (argv[1], "-d", 2) == 0)
{
j = 1;
dev = argv[1] + 2;
}
else if ((dev = GetDevName (SCSI_STRING)) == NULL)
{
fprintf (stderr, "Error : no *scsi*.device in device list\n");
exit (1);
}
pname = argv[0];
if (argc < (j + 2))
{
usage (); /* help inquiry */
exit (1);
}
if (argc < (j + 3))
{
fprintf (stderr, "Error : Not enough params\n");
exit (1);
}
/*
* pick up SCSI id ; do a rough check
*/
if (sscanf (argv[j + 1], "%d", &scsi_id) != 1 || scsi_id < 0)
{
fprintf (stderr, "Error : Bad scsi id\n");
exit (1);
}
if (*(p = argv[j + 2]) != '-')
{
fprintf (stderr, "Error : bad option\n");
exit (1);
}
/*
* now set up structures etc for SCSI xfer
*/
if (init () == FALSE)
{
returnvalue = 1;
goto error;
}
/*
********************** now examine the options
*/
if (argc == (j + 3))
/* commands without parameter */
{
switch (*++p)
{
/*
**** read capacity
*/
case 'c':
if (*++p == 'r')
{
read_capacity (FALSE); /* output raw data */
}
else
{
read_capacity (TRUE); /* output parsed data */
}
break;
/*
**** inquiry (raw)
*/
case 'i':
if (*++p == 'r')
{
inquiry (FALSE); /* output raw data */
}
else
{
inquiry (TRUE); /* output parsed data */
}
break;
/*
**** read TOC
*/
case 't':
if (*(p+1) == 'r')
{
read_toc(0); /* output raw data */
}
else if (*(p+1) == 'l')
{
read_toc(2); /* output long form */
}
else
{
read_toc(1); /* output short form */
}
break;
/*
**** show volume settings
*/
case 'v':
set_volume (-1, -1, -1, -1);
break;
default:
fprintf (stderr, "Error : bad option\n");
returnvalue = 3;
}
}
else if (argc == (j + 4))
/* commands with one parameter */
{
switch (*++p)
{
/*
**** change medium
*/
case 'e':
{
int eject = -1;
if (sscanf (argv[j + 3], "%d", &eject) != 1
|| ((eject != 0) && (eject != 1)))
{
fprintf (stderr, "Error : eject/load control must be 0 or 1\n");
returnvalue = 3;
}
else
{
motor ((eject | 2)); /* eject/insert */
}
}
break;
/*
**** read CD-ROM data block address header
*/
case 'h':
{
ULONG block;
if (sscanf (argv[j + 3], "%lu", &block) != 1)
{
fprintf (stderr, "Error : Bad block no\n");
returnvalue = 3;
}
else
{
if (*++p == 'r')
{
read_cdblockheader (FALSE, block);
}
else
{
read_cdblockheader (TRUE, block);
}
}
}
break;
/*
**** prevent/allow medium removal
*/
case 'l':
{
int lock = -1;
if (sscanf (argv[j + 3], "%d", &lock) != 1
|| ((lock != 0) && (lock != 1)) )
{
fprintf (stderr, "Error : Medium removal control must be 0 or 1\n");
returnvalue = 3;
}
else
{
medium_removal (lock); /* prevent/allow medium removal */
}
}
break;
/*
**** stop/start motor
*/
case 'm':
{
int motoronoff = -1;
if (sscanf (argv[j + 3], "%d", &motoronoff) != 1
|| ((motoronoff != 0) && (motoronoff != 1)) )
{
fprintf (stderr, "Error : motor control must be 0 or 1\n");
returnvalue = 3;
}
else
{
motor (motoronoff); /* turn on/off motor */
}
}
break;
/*
**** read sectors
*/
case 'r':
/*
* get sector #
*/
if (sscanf (argv[j + 3], "%d", &secno) != 1)
{
fprintf (stderr, "Error : Bad sec no\n");
returnvalue = 3;
}
else
{
if (*++p == 't')
{
read_sec (); /* read sector with trackdisk.device */
}
else
{
read_sec_scsi (); /* read sector with scsi */
}
}
break;
/*
**** seek to cylinder containing secno
*/
case 's':
/*
* get sector #
*/
if (sscanf (argv[j + 3], "%d", &secno) != 1)
{
fprintf (stderr, "Error : Bad sec no\n");
returnvalue = 3;
}
else
{
seek ();
}
break;
default:
fprintf (stderr, "Error : bad option\n");
returnvalue = 3;
}
}
else if (argc == (j + 5))
/* commands with two parameters */
{
ULONG startblock, numblocks; /* used by the CDDA commands */
BYTE whichchannel = -1; /* read left / right channel / stereo */
switch (*++p)
{
/*
**** read CD-DA (8 bit left|right mono)
*/
case 'D':
if ((whichchannel = toupper (*(p + 1))) != 'L'
&& whichchannel != 'R')
{
fprintf (stderr, "Error : must be either -DL or -DR\n");
returnvalue = 3;
}
else
{
if (sscanf (argv[j + 3], "%lu", &startblock) != 1
|| sscanf (argv[j + 4], "%lu", &numblocks) != 1)
{
fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
returnvalue = 3;
}
else
{
read_cddaasync (startblock, numblocks, whichchannel,
FALSE, 0);
}
}
break;
#ifdef USE8SVX
/*
**** read CD-DA (output 8SVX 8 bit left|right|stereo)
*/
case '8':
if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
{
fprintf (stderr, "Error : must be -8{L|R|S}\n");
returnvalue = 3;
}
else
{
if (sscanf (argv[j + 3], "%lu", &startblock) != 1
|| sscanf (argv[j + 4], "%lu", &numblocks) != 1)
{
fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
}
else
{
write8svx = TRUE;
read_cddaasync (startblock, numblocks, whichchannel,
FALSE, 0);
}
}
break;
#endif /* USE8SVX */
/*
**** mode sense
*/
case 'o':
{
int control, page;
if (sscanf (argv[j + 3], "%d", &control) != 1 || control < 0 || control > 3)
{
fprintf(stderr, "Error : invalid parameter for control (must be 0-4)\n");
returnvalue = 3;
}
else
{
if (sscanf (argv[j + 4], "%d", &page) != 1 || page < 0 || page > 0x3f)
{
fprintf(stderr, "Error : invalid parameter for page (must be 0-0x3f)\n");
returnvalue = 3;
}
else
{
if (*++p == 'r')
/* raw */
{
mode_sense (FALSE, control, page);
}
else
/* parsed */
{
mode_sense (TRUE, control, page);
}
}
}
}
break;
default:
fprintf (stderr, "Error : bad option\n");
returnvalue = 3;
}
}
else if (argc == (j + 6))
/* commands with 3 parameters */
{
ULONG startblock, numblocks; /* used by the CDDA commands */
BYTE whichchannel = -1; /* read left / right channel / stereo */
unsigned int subcode = 0;
switch (*++p)
{
/*
**** read CD-DA (16 bit raw left|right|stereo)
*/
case 'd':
if ((whichchannel = toupper (*(p + 1))) != 'L'
&& whichchannel != 'R' && whichchannel != 'S')
{
fprintf (stderr, "Error : must be -d{L|R|S}\n");
returnvalue = 3;
}
else
{
if (sscanf (argv[j + 3], "%lu", &startblock) != 1
|| sscanf (argv[j + 4], "%lu", &numblocks) != 1)
{
fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
returnvalue = 3;
}
else
{
if (sscanf (argv[j + 5], "%u", &subcode) != 1)
{
fprintf(stderr, "Error : invalid parameter for subcode\n");
returnvalue = 3;
}
else
read_cddaasync (startblock, numblocks, whichchannel,
TRUE, subcode);
}
}
break;
/*
**** read sub-channel information
*/
case 'u': /* raw */
case 'U': /* parsed */
{
int trackno, subchannelformat, subchannel;
/*
* get sub-channel #
*/
if (sscanf (argv[j + 3], "%d", &subchannel) != 1
|| subchannel < 0 || subchannel >255)
{
fprintf (stderr, "Error : Sub-channel must be 0-255\n");
returnvalue = 3;
}
/*
* get sub-channel data format #
*/
if (sscanf (argv[j + 4], "%d", &subchannelformat) != 1
|| subchannelformat < 0 || subchannelformat >255)
{
fprintf (stderr, "Error : Sub-channel data format must be 0-255\n");
returnvalue = 3;
}
/*
* get track #
*/
if (sscanf (argv[j + 5], "%d", &trackno) != 1 || trackno < 0
|| trackno > 99)
{
fprintf (stderr, "Error : Bad track no (must be 1-99)\n");
returnvalue = 3;
}
else
{
if (*++p == 'r')
{
read_subchannel (FALSE,subchannel, subchannelformat, trackno);
}
else
{
read_subchannel (TRUE,subchannel, subchannelformat, trackno);
}
}
}
break;
default:
fprintf (stderr, "Error : bad option\n");
returnvalue = 3;
}
}
else if (argc == (j + 7))
/* commands with 4 parameters */
{
switch (*++p)
{
/*
**** play audio
*/
case 'p':
{
int starttrack, startindex, endtrack, endindex;
if (sscanf (argv[j + 3], "%d", &starttrack) != 1
|| (starttrack < 1) || (starttrack > 99))
{
fprintf (stderr, "Error : Starting audio track must be in the range 1-99\n");
returnvalue = 3;
goto error;
}
if (sscanf (argv[j + 4], "%d", &startindex) != 1
|| (startindex < 0) || (startindex > 99))
{
fprintf (stderr, "Error : Starting audio track index must be in the range 1-99\n");
returnvalue = 3;
goto error;
}
if (sscanf (argv[j + 5], "%d", &endtrack) != 1
|| (endtrack < 1) || (endtrack > 99))
{
fprintf (stderr, "Error : Ending audio track must be in the range 1-99\n");
returnvalue = 3;
goto error;
}
if (sscanf (argv[j + 6], "%d", &endindex) != 1
|| (endindex < 0) || (endindex > 99))
{
fprintf (stderr, "Error : Ending audio track index must be in the range 1-99\n");
returnvalue = 3;
goto error;
}
play_audio (starttrack, startindex, endtrack, endindex);
}
break;
/*
**** change volume settings
*/
case 'v':
{
int i;
int vol[4];
for (i = 0; i < 4; i++)
{
if (sscanf (argv[j + 3 + i], "%d", &vol[i]) != 1
|| (vol[i] < -1) || (vol[i] > 255))
{
fprintf (stderr, "Error : Volume %d must be in the range -1 - 255\n", i);
returnvalue = 3;
goto error;
}
}
set_volume (vol[0], vol[1], vol[2], vol[3]);
}
break;
default:
fprintf (stderr, "Error : bad option\n");
returnvalue = 3;
}
}
else
{
fprintf (stderr, "Error : bad option\n");
returnvalue = 3;
}
error:
for (i = 0; i < NDBLBUF; i++)
{
if (io_ptr[i])
{
CloseDevice ((struct IORequest *) io_ptr[i]);
DeleteStdIO (io_ptr[i]);
}
if (cdda_buf[i])
FreeMem (cdda_buf[i], MAX_CDDALEN);
if (mp_ptr[i])
DeletePort (mp_ptr[i]);
if (scsi_sense[i])
FreeMem (scsi_sense[i], SENSE_LEN);
if (mono_buf)
FreeMem (mono_buf[i], MAX_CDDALEN / 2);
}
if (toc_buf)
FreeMem (toc_buf, MAX_TOC_LEN);
if (ip_buf)
FreeMem (ip_buf, TD_SECTOR);
if (scsi_data)
FreeMem (scsi_data, MAX_DATA_LEN);
#ifdef _DCC
onbreak(oldbrkhandler);
#endif
exit (returnvalue);
}
/*********************************************************************
*
* Initialization function
*
*/
BOOLEAN
init (void)
{
int i;
if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
{
fprintf (stderr, "AllocMem(0) Fail\n");
return FALSE;
}
if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
{
fprintf (stderr, "AllocMem(2) Fail\n");
return FALSE;
}
if ((toc_buf = (UBYTE *) AllocMem (MAX_TOC_LEN, MEMF_CHIP)) == NULL)
{
fprintf (stderr, "AllocMem(3) Fail\n");
return FALSE;
}
for (i = 0; i < NDBLBUF; i++)
{
if ((scsi_sense[i] = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
{
fprintf (stderr, "AllocMem (scsi_sense[%d]) Fail\n",i);
return FALSE;
}
if ((cdda_buf[i] = (UBYTE *) AllocMem (MAX_CDDALEN, 0)) == NULL)
{
fprintf (stderr, "AllocMem (cdda_buf[%d]) Fail\n",i);
return FALSE;
}
if ((mp_ptr[i] = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
{
fprintf (stderr, "CreatePort (mp_ptr[%d]) Fail\n",i);
return FALSE;
}
if ((io_ptr[i] = (IOSTDREQ *) CreateStdIO (mp_ptr[i])) == NULL)
{
fprintf (stderr, "CreateStdIO (io_ptr[%d]) Fail\n",i);
return FALSE;
}
if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr[i], 0) != 0)
{
fprintf (stderr,
"Error %d while opening SCSI dev \"%s\", unit (%d)\n",
io_ptr[i]->io_Error, dev, scsi_id, i);
return FALSE;
}
if ((mono_buf[i] = (BYTE *) AllocMem (MAX_CDDALEN / 2, 0)) == NULL)
{
fprintf (stderr, "AllocMem (mono_buf[%d]) Fail\n",i);
return FALSE;
}
}
return TRUE;
}
/*********************************************************************
*
* function to read parameter pages from a device
*/
void
mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page)
{
static SCSICMD6 command =
{
SCSI_CMD_MSE, /* 0x1a MODE SENSE scsi command */
PAD, /* LUN | rsrvd. | DBD | rsrvd. */
0, /* PC | Page Code */
PAD, /* rsrvd. */
0, /* allocation length */
PAD /* control */
};
static IDTOSTRING pagecontrolfield[] =
{
0x00, "Current Values",
0x01, "Changeable Values",
0x02, "Default Values",
0x03, "Saved Values",
-1, "Illegal value"
};
UWORD i,j;
int err;
command.b2 = (control<<6) | page;
command.b4 = MAX_DATA_LEN;
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) &command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
else
{
if (parsed == TRUE)
/* output parsed data */
{
printf ("%s\n", id2string(control, pagecontrolfield));
printf ("Mode Parameter Header:\n");
printf (" Mode Data Length: %hu\n", scsi_data[0]);
printf (" Medium Type: %hu\n", scsi_data[1]);
printf (" Device-Specific Parameter: %hu\n", scsi_data[2]);
printf (" Block Descriptor Length: %hu\n", scsi_data[3]);
for (i = 0; i < scsi_data[3]; i +=8) /* print block descriptors */
{
printf("Block Descriptor Density Code: %hu\n",scsi_data[(i)+4]);
printf(" Number of Blocks: %lu\n", (scsi_data[(i)+5]<<16) + (scsi_data[(i)+6]<<8) + (scsi_data[(i)+7]) );
printf(" Byte 4 (reserved): %hu\n", scsi_data[(i)+8]);
printf(" Block length: %lu\n", (scsi_data[(i)+9]<<16) + (scsi_data[(i)+10]<<8) + (scsi_data[(i)+11]) );
}
for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
{
printf("Page Code: %hu\n",scsi_data[i] & 0x3f);
printf(" Page can%s be saved\n", (scsi_data[i] & 0x80) ? "" : " not");
printf(" Page Length: %hu\n", scsi_data[i+1]);
printf(" Mode Parameters:\n");
rawhexasciioutput(&scsi_data[i+2], scsi_data[i+1], 2);
}
}
else
/* output raw data */
{
rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
}
}
}
/*********************************************************************
*
* function to read CD-ROM data block address header
* starting block and number of blocks.
*/
void
read_cdblockheader (BOOLEAN parsed, ULONG block)
{
static SCSICMD10 command =
{
SCSI_CMD_READHEADER, /* 0x44 READ HEADER scsi command */
0, /* LUN | rsrvd. | MSF | rsrvd. */
0, 0, 0, 0, /* Logical Block Address (ULONG) */
PAD, /* reserved */
0,0, /* allocated data length */
PAD /* control */
};
static IDTOSTRING udatafieldcont[] =
{
0x00, "All bytes zero",
0x01, "User Data",
0x02, "User Data",
-1, "Reserved"
};
static IDTOSTRING auxfieldcont[] =
{
0x00, "All bytes zero",
0x01, "L-EC symbols",
0x02, "User Data",
-1, "Reserved"
};
int err;
command.b2 = block>>24;
command.b3 = block>>16;
command.b4 = block>>8;
command.b5 = block;
#if MAX_CDDALEN > 65536
command.b7 = 255;
command.b8 = 255;
#else
command.b7 = MAX_CDDALEN>>8;
command.b8 = MAX_CDDALEN & 0xff;
#endif
if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
(UBYTE *) &command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
else
{
if (parsed == TRUE)
{
printf("User Data Field Contents (2048 bytes): %d = %s\n",
(cdda_buf[0])[0], id2string ((cdda_buf[0])[0], udatafieldcont));
printf("Auxiliary Field Contents ( 288 bytes): %d = %s\n",
(cdda_buf[0])[0], id2string ((cdda_buf[0])[0], auxfieldcont));
printf("Byte 1 (reserved): %d\n",(cdda_buf[0])[1]);
printf("Byte 2 (reserved): %d\n",(cdda_buf[0])[2]);
printf("Byte 3 (reserved): %d\n",(cdda_buf[0])[3]);
printf("Absolute CD-ROM Address: %lu\n",
((cdda_buf[0])[4] << 24) | ((cdda_buf[0])[5] << 16) | ((cdda_buf[0])[6] << 8) | ((cdda_buf[0])[7]));
}
else
{
rawhexasciioutput(cdda_buf[0], 8, 0);
}
}
}
/*********************************************************************
*
* function to read subchannel data audio from Sony CDROM with
* starting block and number of blocks.
*/
void
read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track)
{
static SCSICMD10 command =
{
SCSI_CMD_READSUBCHANNEL, /* 0x42 READ SUB-CHANNEL scsi command */
0, /* LUN | rsrvd. | MSF | rsrvd. */
0x40, /* return Sub-Q Channel data */
0, /* Sub-channel Data Format */
PAD,
PAD,
0, /* Track Number 1-99 */
0,0, /* allocated data length */
PAD /* control */
};
static IDTOSTRING audiostatus[] =
{
0x00, "Audio status byte not supported or not valid",
0x11, "Audio play operation in progress.",
0x12, "Audio play operation paused.",
0x13, "Audio play operation successfully completed.",
0x14, "Audio play operation stopped due to error.",
0x15, "No current audio status to return",
-1, "Reserved, unknown or no audio status"
};
static IDTOSTRING Qfield[] =
{
0x00, "Sub-channel Q mode information not supplied.",
0x01, "Sub-channel Q encodes current position data.",
0x02, "Sub-channel Q encodes media catalog number.",
0x03, "Sub-channel Q encodes ISRC.",
-1, "Reserved"
};
int err;
command.b2 = subchannel;
command.b3 = subchannelformat;
command.b6 = track;
#if MAX_CDDALEN > 65536
command.b7 = 255;
command.b8 = 255;
#else
command.b7 = MAX_CDDALEN & 0xff;
command.b8 = MAX_CDDALEN>>8; /* Allocation length = max. data length */
#endif
if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
(UBYTE *) &command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
else
{
if (parsed == TRUE)
/* parsed output */
{
if (subchannel == 0x40)
{
if (subchannelformat == 0)
{
/* CHANGE - this doesn't work with my Apple CD300!!!!! */
rawhexoutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4);
}
else if (subchannelformat == 1)
{
printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
printf("Audio status: %s\n",id2string ((cdda_buf[0])[1],audiostatus));
printf("Sub-Channel Data Length: %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
printf("Sub-Channel Data Format code (should be 0x01!): %d\n",(cdda_buf[0])[4]);
printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f), Qfield));
printf("Audio with%s pre-emphasis. ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
printf("%s track. ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
printf("Track Number: %d\n", (cdda_buf[0])[6]);
printf("Index Number: %d\n", (cdda_buf[0])[7]);
printf("Absolute CD-ROM Address: %lu\n", ((cdda_buf[0])[8] << 24) | ((cdda_buf[0])[9] << 16) | ((cdda_buf[0])[10] << 8) | ((cdda_buf[0])[11]));
printf("Track Relative CD-ROM Address: %lu\n", ((cdda_buf[0])[12] << 24) | ((cdda_buf[0])[13] << 16) | ((cdda_buf[0])[14] << 8) | ((cdda_buf[0])[15]));
}
else if (subchannelformat == 2)
{
printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
printf("Sub-Channel Data Format code (should be 0x02!): %d\n",(cdda_buf[0])[4]);
printf("Byte 5 (reserved): %02x\n",(cdda_buf[0])[5]);
printf("Byte 6 (reserved): %02x\n",(cdda_buf[0])[6]);
printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
printf("MCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
printf("Media Catalog Number (UPC/Bar Code):\n");
rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
}
else if (subchannelformat == 3)
{
printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
printf("Sub-Channel Data Format code (should be 0x03!): %d\n",(cdda_buf[0])[4]);
printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f) ,Qfield));
printf("Audio with%s pre-emphasis. ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
printf("%s track. ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
printf("Track Number: %d\n", (cdda_buf[0])[6]);
printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
printf("TCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
printf("Track International-Standard-Recording-Code (ISRC):\n");
rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
}
else
{
rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
}
}
else
{
rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
}
}
else
/* raw output */
{
rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
}
}
}
/*********************************************************************
*
* subroutine used to printout raw hex data bytes
*
*/
void
rawhexoutput (UBYTE *p, UWORD numbytes)
{
UWORD i;
for (i = 0; i < numbytes; i++)
{
printf (" %02x", p[i]);
}
printf ("\n");
}
/*********************************************************************
*
* subroutine used to printout raw hex data bytes with the
* corresponding ASCII values and an index
*
*/
void
rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
{
UWORD i, j;
UBYTE *boff, *aoff;
int xxxlen = strlen (" xx"); /* byte */
buffer[5+leadspace] = '=';
for (i = 0; i < numbytes; i += BYTES_PER_LINE)
{
memset (buffer, ' ', sizeof (buffer)); /* put spaces in buffer */
boff = &buffer[7+leadspace];
aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
sprintf (buffer+leadspace, "%04X = ", i); /* add offset */
for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
{
sprintf (boff, " %02X", *p);
*aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
}
buffer[strlen (buffer)] = ' ';
*++aoff = '\n';
*++aoff = '\0';
printf ("%s", buffer);
}
}
/*********************************************************************
*
* function to read digital audio from Sony / Toshiba CD-ROM with
* starting block and number of blocks.
* This version uses asynchronous reads.
*
* outputs LRLRLR pairs of 16 bit digital stereo audio samples,
* 2352 / 2368 / 2448 / 96 bytes per CD-ROM block
*
* or (depending on 'whichchannel')
*
* 8 bit digital audio samples, either the left or right channel.
*/
#ifdef _DCC
__stkargs
#endif
void
read_cddaasync (ULONG startblock, ULONG numblocks, BYTE whichchannel,
BYTE use16bit, unsigned int subcode)
{
static struct CMD_RDCDDA
{
UBYTE cmd; /* READ CD-DA scsi command 0xD8 */
UBYTE pad_a; /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
ULONG lba; /* logical block address MSB, , ,LSB */
ULONG lbn; /* number of blocks to transfer MSB, , ,LSB */
UBYTE subcode; /* special sub code selector:
* 0: normal 2352
* 1: 2368
* 2: 2448
* 3: 96 bytes */
UBYTE cntrl; /* Control */
} command[NDBLBUF];
/*
* TOSHIBA XM3401 specific
*/
static SCSICMD6 modecommand;
static struct cddamodedata
{
UWORD pad0;
UBYTE pad1;
UBYTE bdlength;
ULONG density; /* = densitycode << 24 */
ULONG blocklen;
} newmodedata;
int err, i = 0, j = 0, k = 0, l = 0;
ULONG nblocks = numblocks, xblocks;
finddrivebrand(); /* determine CD-ROM drive */
/*
* TOSHIBA XM3401 specific
*/
if (whatdrive == TOSHIBA3401)
{
/* Read old mode data */
modecommand.opcode = SCSI_CMD_MSE;
modecommand.b1 = 0;
modecommand.b2 = 1;
modecommand.b3 = 0;
modecommand.b4 = MAX_DATA_LEN;
modecommand.control = 0;
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) &modecommand, sizeof (modecommand),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
return;
}
/* Write new mode data */
newmodedata.pad0 = 0;
newmodedata.pad1 = 0;
newmodedata.bdlength = 8;
newmodedata.density = 0x82L << 24;
newmodedata.blocklen = 2352;
modecommand.opcode = SCSI_CMD_MSL;
modecommand.b1 = 0x10;
modecommand.b2 = 0;
modecommand.b4 = sizeof(struct cddamodedata);
if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
(UBYTE *) &modecommand, sizeof (modecommand),
(SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
return;
}
} /* TOSHIBA */
/* reset SCSI status to no command pending
*/
for (i = 0; i < NDBLBUF; i++)
scsi_status[i] = 0;
for (i = 0; ; (++i >= NDBLBUF)? i = 0 : i)
{
if (breakcheck ()) /* ^C ? */
{
/* wait for pending SCSI commands
*/
for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
{
if (scsi_status[i] == 1)
WaitScsiCmd(i);
}
return;
}
if (nblocks > 0)
{
if (scsi_status[i] == 1) /* SCSI command pending? */
{
if ((err = WaitScsiCmd (i)) != 0) /* read failed, reschedule */
{
scsi_status[i] = 0;
do
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
if (breakcheck ()) /* ^C ? */
{
for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
{
if (scsi_status[i] == 1)
WaitScsiCmd(i);
}
return;
}
SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
(UBYTE *) & command[i], sizeof (command[i]),
(SCSIF_READ | SCSIF_AUTOSENSE));
}
while ((err = WaitScsiCmd (i)) != 0);
}
scsi_status[i] = 0; /* no SCSI command pending anymore */
if (use16bit == TRUE && whichchannel == 'S')
/* output 16 bit stereo samples */
{
fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
}
else if (whichchannel == 'L')
/* output left channel */
{
if (use16bit == FALSE)
/* output raw 8 bit left channel */
{
for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
{
(mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
}
else
/* output raw 16 bit left channel */
{
for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
{
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
}
}
else
/* output right channel */
{
if (use16bit == FALSE)
/* output raw 8 bit left channel */
{
for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
{
(mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
}
else
/* output raw 16 bit left channel */
{
for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
{
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
}
}
} /* (scsi_status[i] == 1) ? */
if (whatdrive == TOSHIBA3401)
{
command[i].cmd = SCSI_CMD_READ12; /* TOSHIBA XM3401 */
}
else
{
command[i].cmd = SCSI_CMD_READCDDA; /* Sony CDU-5*1 */
}
command[i].pad_a = 0;
command[i].lba = startblock;
command[i].lbn = xblocks = (nblocks > NUM_OF_CDDAFRAMES)? NUM_OF_CDDAFRAMES : nblocks;
command[i].subcode = subcode;
command[i].cntrl = 0;
startblock += xblocks;
nblocks -= xblocks;
scsi_status[i] = 1; /* Status: SCSI command pending */
SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
(UBYTE *) & command[i], sizeof (command[i]),
(SCSIF_READ | SCSIF_AUTOSENSE));
}
else /* nblocks <= 0 */
{
/* wait for all pending requests */
for (l = 0; l < NDBLBUF; l++)
{
if (scsi_status[i] == 1) /* SCSI command pending ? */
{
if ((err = WaitScsiCmd (i)) != 0) /* SCSI command failed? */
{
scsi_status[i] = 0;
do /* reschedule SCSI command */
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
if (breakcheck ()) /* ^C ? */
{
/* wait for pending SCSI commands
*/
for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
{
if (scsi_status[i] == 1)
WaitScsiCmd(i);
}
return;
}
SendScsiCmd (i, (UBYTE *) cdda_buf[i], scsi_cmd[i].scsi_Length,
(UBYTE *) & command[i], sizeof (command[i]),
(SCSIF_READ | SCSIF_AUTOSENSE));
}
while ((err = WaitScsiCmd (i)) != 0);
}
scsi_status[i] = 0; /* Status: no SCSI command pending */
if (use16bit == TRUE && whichchannel == 'S')
/* output 16 bit stereo samples */
{
fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
}
else if (whichchannel == 'L')
/* output left channel */
{
if (use16bit == FALSE)
/* output raw 8 bit left channel */
{
for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
{
(mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
}
else
/* output raw 16 bit left channel */
{
for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
{
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
}
}
else
/* output right channel */
{
if (use16bit == FALSE)
/* output raw 8 bit left channel */
{
for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
{
(mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
}
else
/* output raw 16 bit left channel */
{
for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
{
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
(mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
}
fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
}
} /* output right channel */
scsi_status[i] = 0;
} /* (scsi_status[i] == 1) ? */
(++i >= NDBLBUF)? i = 0 : i;
} /* for (l = 0; l < NDBLBUF; l++) */
break;
}
}
if (whatdrive == TOSHIBA3401)
{
/*
* TOSHIBA XM3401 specific
*/
/* Write old mode data */
newmodedata.density = ((struct cddamodedata *) scsi_data)->density;
newmodedata.blocklen = ((struct cddamodedata *) scsi_data)->blocklen;
if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
(UBYTE *) &modecommand, sizeof (modecommand),
(SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
}
}
/*********************************************************************
*
* function to read sectors from a starting sector #
* - similar adjacent lines are suppressed on printout.
*
* - uses trackdisk.device
*/
void
read_sec (void)
{
UBYTE *sec_click_ptr; /* click = 16 bytes */
UBYTE *pref;
UBYTE *p;
UWORD j;
UWORD k;
int err;
/*
* keep printing sectors until ^C , or until error
*/
io_ptr[0]->io_Command = CMD_READ;
io_ptr[0]->io_Length = TD_SECTOR;
io_ptr[0]->io_Data = (APTR) ip_buf;
io_ptr[0]->io_Offset = secno * TD_SECTOR; /* will be updated... */
/*
* keep reading sectors : stop on ^C on bad sector #
*/
for (;; ++secno)
{
UBYTE *ss;
UWORD m_sec_offs;
if (breakcheck ()) /* ^C ? */
break;
io_ptr[0]->io_Offset = secno * TD_SECTOR; /* sector offset */
DoIO ((struct IORequest *) io_ptr[0]);
if ((err = io_ptr[0]->io_Error) == 0)
{
printf ("\n");
/*
* scan this sector ...
*/
for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
m_sec_offs < TD_SECTOR;
m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
{
int xxxlen = strlen (" xx"); /* byte */
/*
* don't print line if same contents as previous
*/
if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
{
if (m_sec_offs > 1)
continue; /* same */
}
memset (buffer, ' ', sizeof (buffer)); /* put spaces in buffer */
sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
/* set up for loop */
k = strlen (buffer);
ss = buffer + k;
k += (BYTES_PER_LINE * xxxlen) + 1;
for (p = sec_click_ptr, j = 0;
j < BYTES_PER_LINE;
ss += xxxlen, ++j, ++k)
{
UBYTE dd = *p++;
UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
sprintf (ss, " %02X", dd); /* 2 hex charas */
buffer[k] = que;
}
buffer[strlen (buffer)] = ' ';
buffer[k++] = '\n';
buffer[k++] = '\0';
printf ("%s", buffer);
pref = sec_click_ptr;
}
}
else
{
/* else DoIO error */
fprintf (stderr, "Error : err = %ld , sec = %ld dec , $%lX , [%s]\n",
err, secno, secno, sense_errs (0, err));
return;
}
}
}
/*********************************************************************
*
* function to read sectors from a starting sector #
* - similar adjacent lines are suppressed on printout.
*
* - uses scsi device directly
*/
void
read_sec_scsi (void)
{
static struct CMD_XREAD
{
UBYTE cmd;
UBYTE lba[3];
UBYTE numb_secs;
UBYTE pad;
} command =
{
SCSI_CMD_RD,
0, 0, 0,
0,
PAD
};
UBYTE *sec_click_ptr; /* click = 16 bytes */
UBYTE *pref;
UBYTE *p;
UWORD j;
UWORD k;
int err;
/*
* keep printing sectors until ^C , or until error
*/
/*
* keep reading sectors : stop on ^C on bad sector #
*/
for (;; ++secno)
{
UBYTE *ss;
UWORD m_sec_offs;
command.lba[2] = secno;
command.lba[1] = secno >> 8;
command.lba[0] = (secno >> 8) & 0x1F;
command.numb_secs = 1;
if (breakcheck ()) /* ^C ? */
break;
io_ptr[0]->io_Offset = secno * TD_SECTOR; /* sector offset */
if ((err = DoScsiCmd ((UBYTE *) ip_buf, 512,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
{
printf ("\n");
/*
* scan this sector ...
*/
for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
m_sec_offs < TD_SECTOR;
m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
{
int xxxlen = strlen (" xx"); /* byte */
/*
* don't print line if same contents as previous
*/
if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
{
if (m_sec_offs > 1)
continue; /* same */
}
memset (buffer, ' ', sizeof (buffer)); /* put spaces in buffer */
sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
/* set up for loop */
k = strlen (buffer);
ss = buffer + k;
k += (BYTES_PER_LINE * xxxlen) + 1;
for (p = sec_click_ptr, j = 0;
j < BYTES_PER_LINE;
ss += xxxlen, ++j, ++k)
{
UBYTE dd = *p++;
UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
sprintf (ss, " %02X", dd); /* 2 hex charas */
buffer[k] = que;
}
buffer[strlen (buffer)] = ' ';
buffer[k++] = '\n';
buffer[k++] = '\0';
printf ("%s", buffer);
pref = sec_click_ptr;
}
}
else
{
/* else DoIO error */
fprintf (stderr, "Error : sec = %ld dec , $%lX , [%s]\n",
secno, secno, sense_errs (0, err));
return;
}
}
}
/*********************************************************************
*
* function to prevent/allow allow medium removal
*
*/
void
medium_removal(int lock)
{
static SCSICMD6 command =
{
SCSI_CMD_PAMR, /* 0x1E SCSI Prevent Allow Medium Removal */
0, /* Bit 765 = LUN */
PAD, /* reserved */
PAD, /* reserved */
0, /* Bit 0 = prevent */
PAD, /* reserved */
};
int err;
command.b4 = lock;
if ((err = DoScsiCmd (0, 0,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , [%s]\n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to stop/start motor on SCSI device
* or eject/insert a medium
*
*/
void
motor (int motorstatus)
{
static SCSICMD6 command =
{
SCSI_CMD_SSU, /* 0x1B SCSI Start / Stop Unit */
0,
PAD,
PAD,
0, /* start/stop eject/insert */
PAD,
};
int err;
command.b4 = motorstatus;
if ((err = DoScsiCmd (0, 0,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , [%s]\n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to seek to a cylinder
*
*/
void
seek (void)
{
static struct CMD_SEEK
{
UBYTE cmd;
UBYTE pad_a;
ULONG lba;
UBYTE pad[4];
} command =
{
SCSI_CMD_SKX,
PAD,
0,
PAD, PAD, PAD, PAD
};
int err;
/*
* load sector # (log block addr)
*/
command.lba = secno;
if ((err = DoScsiCmd (0, 0,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err = %ld , sec = %ld dec , $%lX , [%s]\n",
err, secno, secno, sense_errs (0, err));
}
}
/*********************************************************************
*
* what CD-ROM drive?
*
*/
void
finddrivebrand (void)
{
static SCSICMD6 command =
{
SCSI_CMD_INQ, /* 0x12 INQUIRY */
PAD, /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
PAD, /* Page Code */
PAD, /* Reserved */
0, /* Allocation length */
PAD /* Control */
};
int err;
command.b4 = MAX_DATA_LEN; /* Allocation length = max. data length */
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
{
int rem = scsi_cmd[0].scsi_Actual;
if (rem >= 8)
{
if (!memcmp("SONY CD-ROM CDU-8003",
&scsi_data[8], strlen("SONY CD-ROM CDU-8003")))
{
whatdrive = APPLECD300;
}
else if (!memcmp("SONY CD-ROM CDU-8002",
&scsi_data[8], strlen("SONY CD-ROM CDU-8002")))
{
whatdrive = APPLECD150;
}
else if (!memcmp("TOSHIBA",
&scsi_data[8], strlen("TOSHIBA")))
{
whatdrive = TOSHIBA3401;
}
}
else
whatdrive = UNKNOWN;
}
else
/* error */
{
fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to set the output volume of a CD-ROM drive
*
* if (vol0 = vol1 = vol2 = vol3) == -1
* display current volume settings, don't change anything
*
*/
void
set_volume (int vol0, int vol1, int vol2, int vol3)
{
static int err, i, j;
static SCSICMD6 modecommand;
static struct volmodedata
{
UBYTE head[4];
UBYTE page; /* page code 0x0E */
UBYTE plength; /* page length */
UBYTE b2; /* bit 2: Immed, bit 1: SOTC */
UBYTE b3; /* reserved */
UBYTE b4; /* reserved */
UBYTE b5; /* bit 7: APRVal, bit 3-0: format of LBAs / Sec. */
UWORD bps; /* logical blocks per second audio playback */
UBYTE out0; /* lower 4 bits: output port 0 channel selection */
UBYTE vol0; /* output port 0 volume */
UBYTE out1; /* lower 4 bits: output port 1 channel selection */
UBYTE vol1; /* output port 1 volume */
UBYTE out2; /* lower 4 bits: output port 2 channel selection */
UBYTE vol2; /* output port 2 volume */
UBYTE out3; /* lower 4 bits: output port 3 channel selection */
UBYTE vol3; /* output port 3 volume */
} modedata;
for (i = 0; i < 4; i++)
modedata.head[i] = 0;
modecommand.opcode = SCSI_CMD_MSE;
modecommand.b1 = 0;
modecommand.b2 = 0x0E;
modecommand.b3 = 0;
modecommand.b4 = MAX_DATA_LEN;
modecommand.control = 0;
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) &modecommand, sizeof (modecommand),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
return;
}
for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
{
if (vol0 == -1 && vol1 == -1 && vol2 == -1 && vol3 == -1)
{
if ((scsi_data[i] & 0x3f) == 0x0e)
{
printf ("Immed : %s\n", (scsi_data[i+2] & 4)? "yes" : "no");
printf ("SOTC : %s\n", (scsi_data[i+2] & 2)? "yes" : "no");
printf ("APRVal : %svalid\n", (scsi_data[i+5] & 0x80)? "" : "in");
if (scsi_data[i+5] & 0x80)
{
printf ("LBA Format: ");
if ((scsi_data[i+5] & 0x0f) == 0)
printf ("1 second\n");
else if ((scsi_data[i+5] & 0x0f) == 8)
printf ("1/256 second\n");
else
printf ("%hu (reserved)\n", scsi_data[i+5] & 0x0f);
printf ("LBPS : %u\n", scsi_data[i+6]<<8 + scsi_data[i+7]);
}
}
if (scsi_data[i+8] & 0x0f)
printf ("Output 0 : %hu\n", scsi_data[i+8] & 0x0f);
else
printf ("Output 0 : muted\n");
printf ("Volume 0 : %hu\n", scsi_data[i+9]);
if (scsi_data[i+10] & 0x0f)
printf ("Output 1 : %hu\n", scsi_data[i+10] & 0x0f);
else
printf ("Output 1 : muted\n");
printf ("Volume 1 : %hu\n", scsi_data[i+11]);
if (scsi_data[i+12] & 0x0f)
printf ("Output 2 : %hu\n", scsi_data[i+12] & 0x0f);
else
printf ("Output 2 : muted\n");
printf ("Volume 2 : %hu\n", scsi_data[i+13]);
if (scsi_data[i+14] & 0x0f)
printf ("Output 3 : %hu\n", scsi_data[i+14] & 0x0f);
else
printf ("Output 3 : muted\n");
printf ("Volume 3 : %hu\n", scsi_data[i+15]);
}
/* should be 16 bytes */
memcpy (&modedata.page, &scsi_data[i], 16);
}
if (vol0 > -1 || vol1 > -1 || vol2 > -1 || vol3 > -1)
{
modedata.page = 0x0e;
modedata.plength = 0x0e;
if (vol0 >= 0)
modedata.vol0 = vol0;
if (vol1 >= 0)
modedata.vol1 = vol1;
if (vol2 >= 0)
modedata.vol2 = vol2;
if (vol3 >= 0)
modedata.vol3 = vol3;
modecommand.opcode = SCSI_CMD_MSL;
modecommand.b1 = 0x10;
modecommand.b2 = 0;
modecommand.b3 = 0;
modecommand.b4 = sizeof (modedata);
modecommand.control = 0;
if ((err = DoScsiCmd ((UBYTE *) &modedata, sizeof(modedata),
(UBYTE *) &modecommand, sizeof (modecommand),
(SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
return;
}
}
}
/*********************************************************************
*
* function to make an inquiry
*
*/
void
inquiry (BOOLEAN parsedoutput)
{
static SCSICMD6 command =
{
SCSI_CMD_INQ, /* 0x12 INQUIRY */
PAD, /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
PAD, /* Page Code */
PAD, /* Reserved */
0, /* Allocation length */
PAD /* Control */
};
static int err;
command.b4 = MAX_DATA_LEN; /* Allocation length = max. data length */
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
{
int rem = scsi_cmd[0].scsi_Actual;
if (parsedoutput == FALSE)
{
rawhexasciioutput (scsi_data, rem, 0);
}
else
/* parsed output */
{
static IDTOSTRING devicetype[] =
{
0x00, "Direct-access device (e.g., magnetic disk)",
0x01, "Sequential-access device (e.g., magnetic tape)",
0x02, "Printer device",
0x03, "Processor device",
0x04, "Write-once device (e.g., some optical disks)",
0x05, "CD-ROM device",
0x06, "Scanner device",
0x07, "Optical memory device (e.g., some optical disks)",
0x08, "Medium Changer device (e.g., jukeboxes)",
0x09, "Communications device",
0x0A, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
0x0B, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
-1, "Reserved, unknown or no device type"
};
static IDTOSTRING ansiversion[] =
{
0x00, "The device might or might not comply to an ANSI-approved standard.",
0x01, "The device complies to ANSI X3.131-1986 (SCSI-1).",
0x02, "The device complies to (SCSI-2).",
-1, "Reserved",
};
static IDTOSTRING responseformat[] =
{
0x00, "SCSI-1",
0x01, "CCS",
0x02, "SCSI-2",
-1, "Reserved",
};
printf ("Peripherial qualifier: %ld\n", (scsi_data[0] & 0xE0) >> 5);
printf ("Peripherial device type: $%lx, %s\n", (scsi_data[0] & 0x1F), id2string ((scsi_data[0] & 0x1F), devicetype));
printf ("Removable medium: %s\n", (scsi_data[1] & 0x80) ? "yes" : "no");
printf ("Device type modifier: %lx\n", scsi_data[1] & 0x7F);
printf ("ISO Version: %lx\n", (scsi_data[2] & 0xC0) >> 6);
printf ("ECMA Version: %lx\n", (scsi_data[2] & 0x38) >> 3);
printf ("ANSI-Approved Version: %ld, %s\n", scsi_data[2] & 0x07, id2string ((scsi_data[2] & 0x07), ansiversion));
printf ("AENC: %s\n", (scsi_data[3] & 0x80) ? "yes" : "no");
printf ("TrmIOP: does%s support TERMINATE I/O PROCESs message\n", (scsi_data[3] & 0x40) ? "" : "n't");
printf ("Response data format: $%lx, conforms to %s\n", scsi_data[3] & 0x0F, id2string ((scsi_data[3] & 0x0F), responseformat));
printf ("Additional length: $%lx\n", scsi_data[4]);
printf ("INQUIRY[5-6] (Reserved): $%lx, $%lx\n", scsi_data[5], scsi_data[6]);
printf ("RelAdr: does%s support relative addressing\n", (scsi_data[7] & 0x80) ? "" : "n't");
printf ("WBus32: does%s support 32 wide data transfers\n", (scsi_data[7] & 0x40) ? "" : "n't");
printf ("WBus16: does%s support 16 wide data transfers\n", (scsi_data[7] & 0x20) ? "" : "n't");
printf ("Sync: does%s support synchronous transfers\n", (scsi_data[7] & 0x10) ? "" : "n't");
printf ("Linked: does%s support linked commands\n", (scsi_data[7] & 0x08) ? "" : "n't");
printf ("CmdQue: does%s support tagged command queueing\n", (scsi_data[7] & 0x02) ? "" : "n't");
printf ("SftRe: responds to RESET condition with %s RESET alternative\n", (scsi_data[7] & 0x01) ? "soft" : "hard");
printf ("Vendor identification: %.8s\n", &scsi_data[8]);
printf ("Product identification: %.16s\n", &scsi_data[16]);
printf ("Product revision level: %.4s\n", &scsi_data[32]);
printf ("Vendor specific: %.20s\n", &scsi_data[36]);
printf ("Reserved: %.35s\n", &scsi_data[56]);
}
}
else
/* error */
{
fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to read disk capacity
*
*/
void
read_capacity (BOOLEAN parsed)
{
static struct CMD_READ_CAPACITY
{
UBYTE cmd;
UBYTE pad_a;
ULONG lba;
UBYTE pad_b[2];
UBYTE pmi;
UBYTE pad_c;
} command =
{
SCSI_CMD_RCP, /* READ CAPACITY = READ CD-ROM CAPACITY */
PAD, /* LUN | rsrvd. | RelAddr */
0, /* start from sec 0 */
PAD, PAD,
0, /* PMI */
PAD
};
int err;
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
{
if (parsed == TRUE)
/* output parsed data */
{
ULONG sec_no = *((ULONG *) & scsi_data[0]);
ULONG sec_size = *((ULONG *) & scsi_data[4]);
printf ("Max Sec = %7ld , sec size = %4ld (capacity = %7ld KB)\n",
sec_no, sec_size, (sec_no * sec_size) / 1024);
}
else
/* output raw data */
{
rawhexasciioutput (scsi_data, 8, 0);
}
}
else
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to read audio CD TOC (table of contents)
*
*/
void
read_toc (int toclong)
{
static IDTOSTRING Qfield[] =
{
0x00, "Sub-channel Q mode information not supplied.",
0x01, "Sub-channel Q encodes current position data.",
0x02, "Sub-channel Q encodes media catalog number.",
0x03, "Sub-channel Q encodes ISRC.",
-1, "Reserved"
};
static IDTOSTRING Qfieldshort[] =
{
0x00, "not.suppl.",
0x01, "cur.posdt.",
0x02, "med.cat.#.",
0x03, "ISRC",
-1, "reserved"
};
static SCSICMD10 command =
{
SCSI_CMD_READTOC, /* SCSI command read table of contents */
0,
PAD, PAD, PAD, PAD,
0, /* starting track */
0x03, 0x24, /* max. TOC data length on current CD-ROMs 804 bytes
or 100 TOC track descriptors */
PAD
};
int err, tocsize;
UBYTE *tocptr;
if ((err = DoScsiCmd ((UBYTE *) toc_buf, MAX_TOC_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
{
tocsize = (toc_buf[0] << 8) | toc_buf[1]; /* first word encodes length */
if (toclong == 0)
/* display TOC raw form */
{
rawhexasciioutput(toc_buf, (toc_buf[0]<<8 | toc_buf[1]), 0);
}
else if (toclong == 1)
/* display TOC short form */
{
printf ("TOC len: %d\n", tocsize);
printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
if (tocsize >= 2) /* TOC Data Length - FTN - LTN */
tocsize -= 2;
for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
{
printf ("#%3.3d: ADR:%10.10s %-15.15s Dig.copy.%5.5s. %-9.9s %cChan. %ld\n",
tocptr[2],
id2string (((tocptr[1] >> 4) & 0x0F), Qfieldshort),
(tocptr[1] & 0x01) ? "pre-emphasis" : "no-pre-emphasis",
(tocptr[1] & 0x02) ? "prmtd" : "prohb.",
(tocptr[1] & 0x04) ? "Data tr." : "Audio tr.",
(tocptr[1] & 0x08) ? '4' : '2',
((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7]))
);
}
}
else if (toclong == 2)
/* display TOC long form */
{
printf ("TOC len: %d\n", tocsize);
printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
if (tocsize >= 2) /* TOC Data Length - FTN - LTN */
tocsize -= 2;
for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
{
printf ("Track number: %d\n", tocptr[2]);
printf (" ADR: $%lx: %s\n", ((tocptr[1] >> 4) & 0x0F), id2string (((tocptr[1] >> 4) & 0x0F), Qfield));
printf (" Audio with%s pre-emphasis. ", (tocptr[1] & 0x01) ? "" : "out");
printf (" Digital copy %s\n", (tocptr[1] & 0x02) ? "permitted" : "prohibited");
printf (" %s track. ", (tocptr[1] & 0x04) ? "Data" : "Audio");
printf (" %s channel audio. ", (tocptr[1] & 0x08) ? "Four" : "Two");
printf (" Absolute address: %ld\n", ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7])));
}
}
else
/* toclong is neither 0,1 or 2 - this should never happen! */
{
fprintf (stderr, "Error : internal error in read_toc!\n");
}
}
else
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to play audio
*
*/
void
play_audio (int starttrack, int startindex, int endtrack, int endindex)
{
static SCSICMD10 command =
{
SCSI_CMD_PLAYAUDIOTRACKINDEX, /* Play audio track */
PAD, /* LUN */
PAD, /* Reserved */
PAD, /* Reserved */
0, /* Starting Track */
0, /* Starting Index */
PAD, /* Reserved */
0, /* Ending Track */
0, /* Ending Index */
PAD /* Control */
};
int err;
command.b4 = starttrack; /* set audio track to play */
command.b5 = startindex;
command.b7 = endtrack; /* ending track */
command.b8 = endindex;
finddrivebrand (); /* figure out drivetype */
if (whatdrive == APPLECD150)
{
command.opcode = 0xC9; /* Apple CD-150 / Pioneer Opcode for playing audio tracks */
}
if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
(UBYTE *) & command, sizeof (command),
(SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
{
fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
}
}
/*********************************************************************
*
* function to compare two binary strings
*
* returns FALSE if different
*/
int
gcomp (char *p1, char *p2, int len)
{
while (len--)
{
if (*p1++ != *p2++)
return (FALSE);
}
return (TRUE);
}
/*********************************************************************
*
* searches DeviceList for a device name with a given string in it.
* - if found returns with a pointer to it, else NULL
*/
extern struct ExecBase *SysBase;
UBYTE *
GetDevName (char *grep)
{
LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
NODE *ln;
for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
{
UBYTE *p = ln->ln_Name;
while (*p != '.')
{
if (strncmp (p, grep, 4) == 0)
{
return (ln->ln_Name);
}
++p;
}
}
return (NULL); /* not found */
}
/*********************************************************************
*
* Break (^C) function
*
*/
int
breakcheck (void)
{
int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
if (zz)
{
fprintf (stderr, "\n***BREAK: ^C\n");
}
return (zz);
}
#ifdef __SASC
/*********************************************************************
*
* tell SAS to turn of CTRL-C checking
*/
void __regargs
__chkabort (void)
{
}
#endif
/*********************************************************************
*
* function to send a scsi command (uses asynchronous I/O)
*
*/
void
SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
{
io_ptr[req]->io_Length = sizeof (SCSICMD);
io_ptr[req]->io_Data = (APTR) & scsi_cmd[req];
io_ptr[req]->io_Command = HD_SCSICMD;
scsi_cmd[req].scsi_Data = (APTR) data;
scsi_cmd[req].scsi_Length = datasize;
scsi_cmd[req].scsi_SenseActual = 0;
scsi_cmd[req].scsi_SenseData = scsi_sense[req];
scsi_cmd[req].scsi_SenseLength = SENSE_LEN;
scsi_cmd[req].scsi_Command = cmd;
scsi_cmd[req].scsi_CmdLength = cmdsize;
scsi_cmd[req].scsi_Flags = flags;
(void) SendIO ((struct IORequest *) io_ptr[req]);
}
/*********************************************************************
*
* function to wait for an asynchronous scsi command
*
*/
int
WaitScsiCmd (int req)
{
int i;
WaitIO ((struct IORequest *) io_ptr[req]);
if (scsi_cmd[req].scsi_SenseActual)
{
fprintf (stderr, "SENSE_DATA:");
for (i = 0; i < scsi_cmd[req].scsi_SenseActual; i++)
{
fprintf (stderr, " %02x", scsi_cmd[req].scsi_SenseData[i]);
}
fprintf (stderr, "\n");
}
return (io_ptr[req]->io_Error);
}
/*********************************************************************
*
* function to use a scsi command
*
*/
int
DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
{
int i;
io_ptr[0]->io_Length = sizeof (SCSICMD);
io_ptr[0]->io_Data = (APTR) & scsi_cmd[0];
io_ptr[0]->io_Command = HD_SCSICMD;
scsi_cmd[0].scsi_Data = (APTR) data;
scsi_cmd[0].scsi_Length = datasize;
scsi_cmd[0].scsi_SenseActual = 0;
scsi_cmd[0].scsi_SenseData = scsi_sense[0];
scsi_cmd[0].scsi_SenseLength = SENSE_LEN;
scsi_cmd[0].scsi_Command = cmd;
scsi_cmd[0].scsi_CmdLength = cmdsize;
scsi_cmd[0].scsi_Flags = flags;
(void) DoIO ((struct IORequest *) io_ptr[0]);
if (scsi_cmd[0].scsi_SenseActual)
{
fprintf (stderr, "SENSE_DATA:");
for (i = 0; i < scsi_cmd[0].scsi_SenseActual; i++)
{
fprintf (stderr, " %02x", scsi_cmd[0].scsi_SenseData[i]);
}
fprintf (stderr, "\n");
}
return (io_ptr[0]->io_Error);
}
/*********************************************************************
*
* function to return an error string
*
*
*/
UBYTE *
err_str (int err)
{
static UBYTE *errors[] =
{
" cannot issue SCSI command to self ",
" DMA error ",
" illegal or unexpected SCSI phase ",
" SCSI parity error ",
" Select timed out ",
" status and/or sense error "
};
err -= 40;
if ((err < 0) || (err > 5))
return ("Error out-of-range");
else
return (errors[err]);
}
/*********************************************************************
*
* usage function
*
*
*/
void
usage (void)
{
static char *zz[] =
{
"Usage: SCSIutil [-dscsi_dev] <scsi_id> <command>\n",
" -c[r] : Read capacity [raw]\n",
" -d<l|r|s> sec blks sc : Read 16 bit digital audio(start sector/# blocks)(2)\n",
" -D<l|r> sec blks : Read 8 bit digital audio(left or right channel)(3)\n",
" -e <0|1> : Change medium (0=eject, 1=load)\n",
" -i[r] : Inquiry [raw]\n",
" -h[r] blk : Read CD-ROM data block address header\n",
" -l <0|1> : Allow/Prevent medium removal\n",
" -m <0|1> : Stop/Start motor {0=stop, 1=start}\n",
" -o[r] contr page : Mode sense (contr = 0-3))\n",
" -p st si et ei : Play audio CD track (1-99), index (1-99)\n",
" -r[t] sec_no : Read sectors [use trackdisk.device]\n",
" -s sec_no : Seek to sector (5)\n",
" -t[r|l] : Display TOC of an audio CD [raw|long]\n",
" -u[r] chan fmt track : Read CD sub-channel information [raw] (6)\n",
" -v [vl0 vl1 vl2 vl3] : Set output volume channels 0-3 (7)\n",
#ifdef USE8SVX
" -8<l|r|s> sec blks : Read digital audio -> 8SVX (left, right or stereo) (7)\n",
#endif /* USE8SVX */
"\n",
"Note 1: usually scsi_id = (BOARD * 100) + (LUN * 10) + SCSI_TARGET_ID\n",
" 2: with 's' returns LRLRLR pairs of stereo audio, 2352 bytes per block\n",
" sc = Apple subcode (0=2352, 1=2368, 2=2448, 3=96 byte/block)\n",
" 3: converted to 8 bit audio (-d and -D work with Sony CDU 561 & 8003)\n",
" 4: contr 0: current, 1: changeable, 2: default, 3: saved values\n",
" 5: to park heads, try sec_no of -1\n",
" 6: Q-channel = 64, fmt: 0=Sub-Q Channel data,1=current CD-ROM pos.,\n",
" 2=Media Catalog Number (UPC/Bar Code),3=Track ISRC\n",
" 7: use -1 to leave volume of channel as it is, without argument shows\n",
" current volume settings\n",
#ifdef USE8SVX
" 8: output 8SVX IFF (in case of stereo needs to read the CD twice)\n",
#endif /* USE8SVX */
"" /* TERM */
};
int j = 0;
fprintf (stderr, "SCSIutil V%s [%s : %s] - written by Gary Duncan\n",
VERSION, __DATE__, __TIME__, pname);
fprintf (stderr, " (gduncan@philips.oz.au) and Heiko Rath (hr@brewhr.swb.de)\n");
while (*zz[j++])
fprintf (stderr, "%s", zz[j - 1]);
}
/*********************************************************************
*
* sense_errs function ; prints sense errors
*
*
*/
UBYTE *
sense_errs (int req, int err)
{
typedef struct
{
BYTE code;
BYTE sense;
UBYTE *ptr;
} S_ERRS;
/*
* only the likely, interesting ones filled in, e.g media errors
*/
static S_ERRS x[] =
{
0x00, 0x00, "No error",
0x01, 0x04, "?",
0x02, 0x04, "?",
0x03, 0x04, "?",
0x04, 0x02, "?",
0x06, 0x04, "?",
0x09, 0x04, "?",
0x10, 0x03, "?",
0x10, 0x04, "?",
0x11, 0x03, "?",
0x12, 0x03, "?",
0x13, 0x03, "?",
0x14, 0x03, "?",
0x15, 0x04, "Seek error ",
0x17, 0x01, "?",
0x18, 0x01, "?",
0x19, 0x03, "?",
0x1A, 0x05, "?",
0x20, 0x05, "Invalid command op code",
0x21, 0x05, "Illegal sector address",
0x24, 0x05, "?",
0x25, 0x05, "Invalid LUN",
0x26, 0x05, "Invalid field in parameter list",
0x29, 0x06, "?",
0x2A, 0x06, "?",
0x31, 0x03, "?",
0x32, 0x01, "?",
0x32, 0x03, "?",
0x40, 0x04, "?",
0x41, 0x04, "?",
0x42, 0x04, "Power-on diagnostic failure",
0x43, 0x04, "?",
0x45, 0x04, "Select / reselect failure ",
0x47, 0x04, "SCSI Interface Parity Error",
0x48, 0x0B, "?",
0x49, 0x0B, "Illegal message drive can't support",
-1, -1, "ILLEGAL sense!!"
};
int j = 0;
UBYTE *p;
char sense;
char code;
/*
* verify that sense data looks valid
*/
if (((scsi_cmd[req].scsi_Status & 2) == 0) ||
(scsi_cmd[req].scsi_SenseActual < OFFS_KEY))
{
return ("");
}
sense = scsi_cmd[req].scsi_SenseData[OFFS_KEY] & 0xF;
code = scsi_cmd[req].scsi_SenseData[OFFS_CODE];
do
{
p = x[j].ptr;
if ((x[j].code == code) && (x[j].sense == sense))
break;
} while (x[j++].code != -1);
return (p);
}
/*********************************************************************
*
* id2string function ; return pointer to string for matching id
*
*/
UBYTE *
id2string (int id, IDTOSTRING * idtable)
{
int j = 0;
UBYTE *p;
do
{
p = idtable[j].ptr;
if (idtable[j].code == id)
break;
} while (idtable[j++].code != -1);
return p;
}